;(function(factory) {
	if(typeof define === 'function' && define.amd) {
		define(['jquery', 'frame/XFrame_Graph'], factory);
	}else {
		factory(jQuery, XFrame_Graph, window);
	}
}(function($, XFrame_Graph, global) {
	'use strict';
	var BaseShape, makeDefaultEvent, 
		defaultMouseInEvent, defaultMouseOutEvent,
		defaultActiveEvent, defaultInActiveEvent,
		defaultDragEvent;
	
	defaultMouseInEvent = function(){
		if(this.isActive){
			this.status = 'active';
		}else{
			this.status = 'hover';
		}

		this.refresh();
		return !!this.parentShape;
	};
	
	defaultMouseOutEvent = function(){
		if(this.isActive){
			this.status = 'active';
		}else{
			this.status = 'default';
		}
		this.refresh();
	};
	
	defaultActiveEvent = function(){
		if(!this.canActive){
			return;
		}
		this.isActive = true;
		this.status = 'active';
		this.refresh();
	};
	
	defaultInActiveEvent = function(e, iscancel){
		if(iscancel && !this.canInActive){
			return;
		}
		this.isActive = false;
		this.status = 'default';
		this.refresh();
	};
	
	defaultDragEvent = function(e, dragInfo, nowScale, isvml){
	    var mx = e.mx, my = e.my, xOffset =  0, yOffset = 0, xRealOffset = 0, yRealOffset = 0;
	    
	    nowScale = nowScale | 1;
	   
	    if(this.spDragMode && this.resizable){
	    	xOffset = (mx - dragInfo[0]) / nowScale;
	    	yOffset = (my - dragInfo[2]) / nowScale;
        	switch(this.spDragMode){
        		case 't' : 
        			yRealOffset = dragInfo[7] - yOffset < this.minHeight ? dragInfo[7] - this.minHeight : yOffset;
        			this.posY = dragInfo[3] + yRealOffset;
        			this.height = dragInfo[7] - yRealOffset;
        			break;
        		case 'b' : 
        			yRealOffset = dragInfo[7] + yOffset < this.minHeight ? this.minHeight - tdragInfo[7] : yOffset;
        			this.height = dragInfo[7] + yRealOffset;
        			break;
        		case 'l' :
        			xRealOffset = dragInfo[6] - xOffset < this.minWidth ? dragInfo[6] - this.minWidth : xOffset;
        			this.posX = dragInfo[1] + xRealOffset;
        			this.width = dragInfo[6] - xRealOffset;
        			break;
        		case 'r' :
        			xRealOffset = dragInfo[6] + xOffset < this.minWidth ? this.minWidth - dragInfo[6] : xOffset;
        			this.width = dragInfo[6] + xRealOffset;
        			break;
        		case 'tl':
        			xRealOffset = dragInfo[6] - xOffset < this.minWidth ? dragInfo[6] - this.minWidth : xOffset;
        			yRealOffset = dragInfo[7] - yOffset < this.minHeight ? dragInfo[7] - this.minHeight : yOffset;
        			this.posX = dragInfo[1] + xRealOffset;
        			this.posY = dragInfo[3] + yRealOffset;
        			this.width = dragInfo[6] - xRealOffset;
        			this.height = dragInfo[7] - yRealOffset;
        			break;
        		case 'tr':
        			xRealOffset = dragInfo[6] + xOffset < this.minWidth ? this.minWidth - dragInfo[6] : xOffset;
        			yRealOffset = dragInfo[7] - yOffset < this.minHeight ? dragInfo[7] - this.minHeight : yOffset;
        			this.posY = dragInfo[3] + yRealOffset;
        			this.width = dragInfo[6] + xRealOffset;
        			this.height = dragInfo[7] - yRealOffset;
        			break;
        		case 'bl':
        			xRealOffset = dragInfo[6] - xOffset < this.minWidth ? dragInfo[6] - this.minWidth : xOffset;
        			yRealOffset = dragInfo[7] + yOffset < this.minHeight ? this.minHeight - dragInfo[7] : yOffset;
        			this.posX = dragInfo[1] + xRealOffset;
        			this.width = dragInfo[6] - xRealOffset;
        			this.height = dragInfo[7] + yRealOffset;
        			break;
        		case 'br':
        			xRealOffset = dragInfo[6] + xOffset < this.minWidth ? this.minWidth - dragInfo[6] : xOffset;
        			yRealOffset = dragInfo[7] + yOffset < this.minHeight ? this.minHeight - dragInfo[7] : yOffset;
        			this.width = dragInfo[6] + xRealOffset;
        			this.height = dragInfo[7] + yRealOffset;
        			break;
        	}
        	this.updateCommands();
        	this.refresh();
        }else if(!this.selfControlDrag && !this.spDragMode){   
        	if(!this.dragable)   {
        		return;
        	} 
            this.posX = dragInfo[1] + (mx - dragInfo[0]) / nowScale;
            this.posY = dragInfo[3] + (my - dragInfo[2]) / nowScale;
            
            this.posX = (this.posX < 0) ? 0 : (this.posX > dragInfo[4] ? dragInfo[4] : this.posX);
            this.posY = (this.posY < 0) ? 0 : (this.posY > dragInfo[5] ? dragInfo[5] : this.posY);
            this.updateCommands();
            
            this.refresh();
        } 
	};
	
	makeDefaultEvent = function(){
		this.bindEvent('mousein', defaultMouseInEvent);
		this.bindEvent('mouseout', defaultMouseOutEvent);
		if(this.canActive){
			this.bindEvent('active', defaultActiveEvent);
			this.bindEvent('inactive', defaultInActiveEvent);
		}
		if(this.dragable || this.resizable){
		    this.bindEvent('dragging', defaultDragEvent);
		}
	};
	
	BaseShape = XFrame_Graph._createClass({
		init : function(conf){
			conf = conf || {};
			this.width = conf.width || 100;
			this.height = conf.height || 100;
			this.posX = conf.posX || 0;
			this.posY = conf.posY || 0;
			//this.absolutePosX = conf.posX || 0;
			//this.absolutePosY = conf.posY || 0;
			this.resizable = !!conf.resizable;
			this.dragable = !!conf.dragable;
			this.zcontext = (typeof conf.parentShape === 'string' || !conf.parentShape) ? conf.parentShape : conf.parentShape.uuid;
			this.parentShape = conf.parentShape;
			this.zindex = conf.zindex || 0;
			this.isActive = false;
			this.isAlwaysOnTop = false;
			this.canActive = true;
			this.canInActive = true;
			this.minWidth = 100;
			this.minHeight = 100;
			this.eventsDef = {};
			this.uuid = XFrame_Graph._genId();
			this.showImmediately = !!conf.show;
			this.status = 'default';
			this.isHidden = !!conf.hidden;
			
			this.selfControlDrag = !!conf.selfControlDrag;
			this.dragged = false;
			
			this.borderColor = conf.borderColor || '#aaaaaa';
			
			this.disableEvents = false;

			this.spDragMode = null;

			this.canProcessRootEvent = false;

		},
		regist : function(){
		    makeDefaultEvent.call(this);
			XFrame_Graph.registShape(this);
		},
		getAbsolutePosX : function(){
			if(!this.parentShape){
				return this.posX;
			}
			return this.parentShape.getAbsolutePosX() + this.posX;
		},
		getAbsolutePosY : function(){
			if(!this.parentShape){
				return this.posY;
			}
			return this.parentShape.getAbsolutePosY() + this.posY;
		},
		drawDefine : function(){
			var dd = new XFrame_Graph.drawDefiner();
			dd.style('Stroke', this.borderColor);
			dd.draw('Rect', this.posX, this.posY, this.width, this.height);
			
			dd.changeEditType('hover');
			dd.style('Stroke', this.borderColor);
			dd.style('Fill', this.borderColor);
			dd.draw('Rect', this.posX, this.posY, this.width, this.height);
			
			dd.changeEditType('active');
			dd.style('Stroke', this.borderColor);
			dd.style('Fill', this.borderColor);
			dd.draw('Rect', this.posX, this.posY, this.width, this.height);
			
			return dd.getCommands();
		},
		updateCommands : function(){
			XFrame_Graph.reGetCommands(this.uuid);
		},
		rangeDefine : function(){
			
		},
		onEvent : function(en, eh){
		    if(this.disableEvents) return;
			if(!this.eventsDef[en]){
				this.eventsDef[en] = [];
			}
			this.eventsDef[en].length = 0;
			this.eventsDef[en].push(eh);
		},
		bindEvent : function(en, eh){
		    if(this.disableEvents) return;
			if(!this.eventsDef[en]){
				this.eventsDef[en] = [];
			}
			this.eventsDef[en].push(eh);
		},
		unbindEvent : function(en){
		    if(this.disableEvents) return;
			if(en){
				this.eventsDef[en] = null;
			}else{
				this.eventsDef = {};
			}
		},
		triggerEvent : function(en, eobj){
		    if(this.disableEvents) return;
		   
			var efn, args = Array.prototype.slice.call(arguments, 1), res = true ;
			if(efn = this.eventsDef[en]){
			    
				$.each(efn, $.proxy(function(idx, fn){
					res = res && (fn.apply(this, args) !== false);
					return res;
				}, this));
			}
			return res;
		},
		refresh : function(){
			XFrame_Graph.refresh();
		},
		show : function(){
		    this.isHidden = false;
		    this.refresh();
		},
		hide : function(){
		    this.isHidden = true;
		    this.refresh();
		},
		toggleDisplay : function(){
		    this.isHidden = !this.isHidden;
		    this.refresh();
		}
	});
	
	
	global && (global.BaseShape = BaseShape);
	return BaseShape;
}));